#!pip install plotly==4.12.0
#!pip install yellowbrick
#!pip install -U yellowbrick
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import scipy.cluster.hierarchy as shc
import time
from sklearn.cluster import AgglomerativeClustering
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.cluster import KMeans
from yellowbrick.cluster.elbow import kelbow_visualizer
from kneed import KneeLocator
from sklearn.manifold import TSNE
from sklearn.preprocessing import OrdinalEncoder
import plotly.express as px
import plotly.graph_objects as go
import plotly.offline as py
py.init_notebook_mode()
%matplotlib inline
sns.set(style = "darkgrid")
ini = time.time()
fonte = "https://github.com/alura-cursos/imersao-dados-2-2020/blob/master/MICRODADOS_ENEM_2019_SAMPLE_43278.csv?raw=true"
df = pd.read_csv(fonte)
df.head()
# Conhecendo a estrutura do dataset
df.shape
# Conhecendo as colunas existentes
df.columns.values
# Pré-análise das provas do enem
df.rename(columns = {
'NU_NOTA_CN':'NOTAS_CIENCIAS_NATUREZA',
'NU_NOTA_CH': 'NOTA_HUMANAS',
'NU_NOTA_MT': 'NOTA_MATEMATICA',
'NU_NOTA_LC': 'NOTA_LINGUAS',
'NU_NOTA_REDACAO': 'NOTA_REDACAO'
}, inplace = True)
tests = [
"NOTAS_CIENCIAS_NATUREZA",
"NOTA_HUMANAS",
"NOTA_MATEMATICA",
"NOTA_LINGUAS",
"NOTA_REDACAO"
]
df[tests].describe()
df[tests].boxplot(
grid=True,
figsize= (10,8)
)
#plt.savefig('./ImgOut/boxplot_notas_provas.png')
# Colunas com dados null
df.columns[df.isnull().any()]
# Limpando o dataset, removendo colunas que não serão utilizadas na análise
del df['NU_INSCRICAO']
del df['CO_MUNICIPIO_NASCIMENTO'] #codigo municipio de nascimento
del df['CO_UF_NASCIMENTO'] #codigo do uf de nascimento
del df['CO_ESCOLA'] #codigo escola
del df['CO_MUNICIPIO_ESC'] #codigo municipio da escola
del df['CO_UF_ESC'] #codigo uf da escola
del df['TP_DEPENDENCIA_ADM_ESC'] #dependencia administrativa escola
del df['TP_LOCALIZACAO_ESC'] #localizacao escola ?
del df['TP_SIT_FUNC_ESC'] #situação de funcionamento ?
del df['CO_PROVA_CN'] #codigo da prova 1
del df['CO_PROVA_CH'] #codigo da prova 2
del df['CO_PROVA_LC'] #codigo da prova 3
del df['CO_PROVA_MT'] #codigo da prova 4
del df['TX_RESPOSTAS_CN']
del df['TX_RESPOSTAS_CH']
del df['TX_RESPOSTAS_LC']
del df['TX_RESPOSTAS_MT']
del df['TX_GABARITO_CN']
del df['TX_GABARITO_CH']
del df['TX_GABARITO_LC']
del df['TX_GABARITO_MT']
del df['TP_ENSINO']
del df['NO_MUNICIPIO_ESC']
del df['SG_UF_ESC']
# Removendo registros sem notas
df.dropna(axis= 0, subset=tests, inplace= True)
# Transformando as respostas em valores numéricos para análise
col_questions = [
'Q001','Q002','Q003','Q004','Q005',
'Q006','Q007','Q008','Q009','Q010',
'Q011','Q012','Q013','Q014','Q015',
'Q016','Q017','Q018','Q019','Q020',
'Q021','Q022','Q023','Q024','Q025'
]
ord_enc = OrdinalEncoder()
df[col_questions] = ord_enc.fit_transform(df[col_questions])
df[
[
'Q001','Q002','Q003','Q004','Q005',
'Q006','Q007','Q008','Q009','Q010'
]
].head()
# Reduzindo a dimensionalidade dos valores relacionados a quantidade de pessoas na residência
df.loc[df['Q005']>7, 'Q005'] = 7
# Catagorizando os dados relacionados a renda dos participantes
# adaptado de https://economia.uol.com.br/colunas/econoweek/2020/09/25/classe-a-b-ou-c.htm#:~:text=Na%20classe%20C%2C%20est%C3%A3o%20as,%2C01%20e%20R%24%2020.900.
df.loc[df['Q006']<=3, 'Q006'] = 0 #classe E
df.loc[(df['Q006']>0) & (df['Q006']<=6), 'Q006'] = 1 #classe D
df.loc[(df['Q006']>1) & (df['Q006']<=12), 'Q006'] = 2 #classe C
df.loc[(df['Q006']>2) & (df['Q006']<=15), 'Q006'] = 3 #classe B
df.loc[df['Q006']>3, 'Q006'] = 4 #classe A
df.Q006.value_counts()
df_explore = df.copy()
df_explore = df_explore.dropna(axis=0)
# remove os dados de "não sei" sobre a escolaridade dos responsaveis
df_explore = df_explore.loc[df_explore['Q001'] <= 6]
df_explore = df_explore.loc[df_explore['Q002'] <= 6]
df_explore.Q001.value_counts()
# Normalizando os dados relacionados ao tipo de escola do participante
df_explore = df_explore.loc[df_explore['TP_ESCOLA'].isin([2, 3])]
df_explore['TIPO_ESCOLA'] = ''
df_explore.loc[df_explore['TP_ESCOLA']==2, 'TIPO_ESCOLA'] = 'Publica'
df_explore.loc[df_explore['TP_ESCOLA']==3, 'TIPO_ESCOLA'] = 'Privada'
df_explore.loc[df_explore['TP_ESCOLA']==2, 'TP_ESCOLA'] = 0
df_explore.loc[df_explore['TP_ESCOLA']==3, 'TP_ESCOLA'] = 1
school = pd.get_dummies(df_explore.TIPO_ESCOLA.astype(str))
name_school = school.columns.tolist()
df_explore = pd.concat([df_explore, school], axis=1)
df_explore.TP_ESCOLA.value_counts()
# Normalizando os dados relacionados a raça/cor da participante
df_explore = df_explore.loc[df_explore['TP_COR_RACA'].isin([1, 2, 3, 4])]
df_explore['RACA'] = ''
df_explore.loc[df_explore['TP_COR_RACA']==1, 'RACA'] = 'Branca'
df_explore.loc[df_explore['TP_COR_RACA']==2, 'RACA'] = 'Preta'
df_explore.loc[df_explore['TP_COR_RACA']==3, 'RACA'] = 'Parda'
df_explore.loc[df_explore['TP_COR_RACA']==4, 'RACA'] = 'Amarela'
df_explore.loc[df_explore['TP_COR_RACA']==5, 'RACA'] = 'Indigena'
races = pd.get_dummies(df_explore.TP_COR_RACA.astype(str))
name_races = races.columns.tolist()
df_explore = pd.concat([df_explore, races], axis=1)
# Criação de uma coluna com a soma e a média das notas
df_explore['SOMA_NOTAS'] = df_explore['NOTAS_CIENCIAS_NATUREZA'] + df_explore['NOTA_HUMANAS'] + df_explore['NOTA_MATEMATICA'] + df_explore['NOTA_LINGUAS'] + df_explore['NOTA_REDACAO']
df_explore['MEDIA_NOTAS'] = df_explore['SOMA_NOTAS'] / 5
Nova análise e exploração dos dados que serão utilizados em ML
fig = px.box(
df_explore,
y='MEDIA_NOTAS',
title='Distribuição de notas médias',
labels={'MEDIA_NOTAS':'Média de Notas'}
)
fig.show()
#fig.write_image('./ImgOut/distro_notas.png')
#Removendo os outilers relacionados as notas
df_explore = df_explore.loc[(df_explore['MEDIA_NOTAS'] >= 285.) & (df_explore['MEDIA_NOTAS'] <= 757.)]
fig = px.box(
df_explore,
y=tests,
color='RACA',
title='Distribuição de notas médias por tipo de prova e por cor/raça',
labels={
'value':'Média de notas',
'variable':'Cor/Raça'
}
)
fig.update_traces(quartilemethod="exclusive")
fig.show()
#fig.write_image('./ImgOut/distro_notas_etnia.png')
fig = px.box(
df_explore,
y='MEDIA_NOTAS',
x='RACA',
title='Distribuição de notas médias por raça/cor',
labels={
'MEDIA_NOTAS':'Média de notas',
'RACA':'Distribuição étnica'
}
)
fig.show()
#fig.write_image('./ImgOut/distro_notas_etnia2.png')
fig = px.box(
df_explore,
y='MEDIA_NOTAS',
x='TIPO_ESCOLA',
title='Distribuição de notas médias por tipo de escola',
labels={
'MEDIA_NOTAS':'Média de notas',
'TIPO_ESCOLA':'Tipo de escola'
}
)
fig.show()
#fig.write_image('./ImgOut/distro_notas_tipo_escola.png')
fig = px.box(
df_explore,
y=tests,
color='TIPO_ESCOLA',
title='Distribuição de notas médias por tipo de prova e por tipo de escola',
labels={
'value':'Média de notas',
'variable':'Tipo de prova'
}
)
fig.update_traces(quartilemethod="exclusive")
fig.show()
#fig.write_image('./ImgOut/distro_provas_escola.png')
# Função para gerar uma table
def build_table(df, index, colunms):
df2 = df[index.keys()]
pieces = []
for col in df2.columns:
tmp_series = df2[col].value_counts()
tmp_series.name = col
pieces.append(tmp_series)
df_value_counts = pd.concat(pieces, axis=1)
df_t = df_value_counts.T
df_t.rename(columns=colunms,
index=index, inplace=True)
return df_t
questions_escola = {
'TP_ESCOLA': 'Estou em escola particular?'
}
build_table(df_explore, questions_escola, {0: 'Não', 1: 'Sim'})
fig = px.box(
df_explore,
y='MEDIA_NOTAS',
x='Q001',
title='Até que série seu pai, ou o homem responsável por você, estudou?',
labels={
'MEDIA_NOTAS':'Média de Notas',
'Q001':'Grau de instrução do pai ou homem responsável'
}
)
fig.show()
#fig.write_image('./ImgOut/distro_notas_gi_pai.png')
questions_grau_pai = {
'Q001': 'Grau de instrução do pai ou homem responsávael'
}
fig = px.box(
df_explore,
y='MEDIA_NOTAS',
x='Q002',
title='Grau de instrução da mãe ou mulher responsável',
labels={
'MEDIA_NOTAS':'Média de Notas',
'Q002':'Grau de instrução da mãe ou mulher responsável'
}
)
fig.show()
#fig.write_image('./ImgOut/distro_notas_gi_mae.png')
fig = px.box(
df_explore,
y='MEDIA_NOTAS',
x='Q005',
title='Número de pessoas na residência',
labels={
'MEDIA_NOTAS':'Média de Notas',
'Q005':'Número de pessoas (núm. 7 equivale a 7 ou mais)'
}
)
fig.show()
#fig.write_image('./ImgOut/distro_notas_num_pessoas.png')
fig = px.box(
df_explore,
y='MEDIA_NOTAS',
x='Q006',
title='Nota por renda mensal familiar',
labels={
'MEDIA_NOTAS':'Média de Notas',
'Q006':'Grupos de renda familiar'
}
)
fig.show()
#fig.write_image('./ImgOut/distro_notas_renda.png')
fig = px.box(
df_explore,
y='MEDIA_NOTAS',
x='Q007',
title='Possui empregada(o) doméstica(o)?',
labels={
'MEDIA_NOTAS':'Média de Notas',
'Q007':'0 - Não possui, 1- um ou dois dias por semana, 2 - três ou quatro dias por semana, 3 - cinco ou mais dias por semana'
}
)
fig.show()
#fig.write_image('./ImgOut/distro_notas_empregada.png')
fig = px.box(
df_explore,
y='MEDIA_NOTAS',
x='Q008',
title='Possui banheiros na residência?',
labels={
'MEDIA_NOTAS':'Média de Notas',
'Q008':'Quantidade de banheiros na residência (núm. 4 equivale a 4 ou mais)'
}
)
fig.show()
#fig.write_image('./ImgOut/distro_notas_banheiro.png')
fig = px.box(
df_explore,
y='MEDIA_NOTAS',
x='Q009',
title='Possui quartos na residência?',
labels={
'MEDIA_NOTAS':'Média de Notas',
'Q009':'Número de quartos na residência (núm. 4 equivale a 4 ou mais)'
}
)
fig.show()
#fig.write_image('./ImgOut/distro_notas_quarto.png')
fig = px.box(
df_explore,
y='MEDIA_NOTAS',
x='Q010',
title='Possui carros na residência?',
labels={
'MEDIA_NOTAS':'Média de Notas',
'Q010':'Número de carros na residência (núm. 4 equivale a 4 ou mais)'
}
)
fig.show()
#fig.write_image('./ImgOut/distro_notas_carro.png')
Questões de 1 a 10, exceto Q003 e Q004, que diz respeito a área de atuação profissional dos pais ou responsáveis;
Média de notas;
Tipo de ensino cursado na educação básica (escola pública ou privada);
cols_sample = [
'MEDIA_NOTAS',
'Q001',
'Q002',
'Q005',
'Q006',
'Q007',
'Q008',
'Q009',
'Q010',
'TP_ESCOLA'
]
# Amostragem de dados para os testes: 5000 instâncias
sample_kmeans = df_explore[cols_sample].sample(n=10000, random_state=1)
sample_kmeans = sample_kmeans.astype(int)
# Avaliação da correção entre variáveis
# (não foi encontrada nenhuma variável com correlão muito alta, para ser retirada do dataset)
corr = sample_kmeans.corr()
plt.figure(figsize = (15, 10))
sns.heatmap(
corr,
xticklabels=corr.columns.values,
yticklabels=corr.columns.values,
annot = True,
fmt='.2g'
)
#plt.savefig('./ImgOut/heat_map.png')
# Removendo a coluna média das notas, para não interferir no resultado dos agrupamentos
media_notas = sample_kmeans['MEDIA_NOTAS']
del sample_kmeans['MEDIA_NOTAS']
# Calcula a inertia, para saber o K ótimo
inertia = []
qtd_testes = 15
for n in range(1 , qtd_testes):
algorithm = (
KMeans(
n_clusters = n
)
)
algorithm.fit(sample_kmeans)
inertia.append(algorithm.inertia_)
# Plotando valores da inertia
plt.figure(1 , figsize = (15 ,6))
plt.plot(np.arange(1 , qtd_testes) , inertia , 'o')
plt.plot(np.arange(1 , qtd_testes) , inertia , '-' , alpha = 0.5)
plt.xlabel('Número de Clusters')
plt.xticks(ticks=np.arange(1 , qtd_testes))
plt.ylabel('Soma das Distâncias Q intra Clusters')
#plt.savefig('./ImgOut/elbow.png')
plt.show()
# Visualização do cotovelo pelo método Elbow, com a seleção do "k-ótimo"
kelbow_visualizer(
KMeans(),
sample_kmeans,
k=(
1,
qtd_testes
)
)
kl = KneeLocator(range(1, qtd_testes), inertia, curve="convex", direction="decreasing")
numero_de_clusters = kl.elbow
numero_de_clusters
# Inicializando e computando o KMeans :
algorithm = (
KMeans(
n_clusters=numero_de_clusters
)
)
algorithm.fit(sample_kmeans)
# Reduzindo a dimensionalidade par uma melhor visualização
time_start = time.time()
tsne = TSNE()
visualizacao = tsne.fit_transform(sample_kmeans)
print('t-SNE executado! Tempo decorrido desde o início: ',format(time.time()-time_start), 'seconds')
sns.set(
rc={
'figure.figsize': (13, 13)
}
)
sns.scatterplot(
x=visualizacao[:, 0],
y=visualizacao[:, 1],
hue=algorithm.labels_,
palette=sns.color_palette(
'Set1',
numero_de_clusters
)
)
#plt.savefig('./ImgOut/clustering.png')
sample_kmeans['Categoria'] = algorithm.labels_
# Scaler da média das notas
start = 0
end = 10
width = end - start
scaler_media = (media_notas - media_notas.min())/(media_notas.max() - media_notas.min()) * width + start
sample_kmeans['MEDIA_NOTAS'] = scaler_media
sample_kmeans.rename(
columns = {
'Q001':'Grau de instrução do pai',
'Q002':'Grau de instrução da mãe',
'Q005':'Número de pessoas na residência',
'Q006':'Grupo de renda mensal',
'Q007':'Possui empregada(o) doméstica(o) - dias',
'Q008':'Qtd banheiro na residência',
'Q010':'Quantidade de carros na residência',
'Q009':'Quantidade de quartos na residência',
'TP_ESCOLA': 'Tipo de escola',
'MEDIA_NOTAS': 'Média da nota'
},
inplace = True
)
sample_kmeans.groupby("Categoria").aggregate("mean").plot.bar(figsize=(15,10))
plt.title("Dados por categoria")
#plt.savefig('./ImgOut/agrupamento_final.png')
endd = time.time()
et = (endd - ini)/60
print('Elapsed Application time: {:.2f}'.format(et),' minutes')
Grupo A - 0:
Grupo B - 1:
Grupo C - 2:
Grupo D - 3: